/* LEDC (LED Controller) basic example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/

#include "ledc.h"
#include "driver/gpio.h"
#include <esp_log.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "nvs_storage.h"
#include "freertos/FreeRTOS.h"
#include "freertos/timers.h"

#define LEDC_TIMER              LEDC_TIMER_0
#define LEDC_MODE               LEDC_LOW_SPEED_MODE
#define LEDC_OUTPUT_IO_1         (33) // Define the output GPIO
#define LEDC_OUTPUT_IO_2         (25) // Define the output GPIO
#define LEDC_OUTPUT_IO_3         (26) // Define the output GPIO
#define LEDC_CHANNEL_R            LEDC_CHANNEL_0
#define LEDC_CHANNEL_G            LEDC_CHANNEL_1
#define LEDC_CHANNEL_B            LEDC_CHANNEL_2
#define LEDC_DUTY_RES           LEDC_TIMER_13_BIT // Set duty resolution to 13 bits
#define LEDC_DUTY               (4095) // Set duty to 50%. ((2 ** 13) - 1) * 50% = 4095
#define LEDC_FREQUENCY          (5000) // Frequency in Hertz. Set frequency at 5 kHz


#define NUM_COLOR               (9u)
static const char *TAG = "LEDC";

// LED状态
static  bool led_state = false;
static led_type_t led_type = COMMON_CATHODE;
static TimerHandle_t led_timer;
static unsigned int led_rest_time = 0;

led_color_t color[NUM_COLOR] = {
    {.r = 0xff,.g = 0xff,.b = 0xff},//current color
    {.r = 0xff,.g = 0x00,.b = 0x00},//red
    {.r = 0x00,.g = 0xff,.b = 0x00},//green
    {.r = 0x00,.g = 0x00,.b = 0xff},//blue
    {.r = 0x00,.g = 0xff,.b = 0xff},//sky blue
    {.r = 0xff,.g = 0x00,.b = 0xff},//purple
    {.r = 0xff,.g = 0xff,.b = 0x00},//yellow
    {.r = 0xff,.g = 0xff,.b = 0xff},//white
};

static unsigned char selected_color_index = 1;
static led_color_t saved;

void vTimerCallback( TimerHandle_t xTimer )
{
    led_rest_time--;
    if(led_rest_time==0){
        set_led_status(false);
        xTimerStop( xTimer, 0 );
    }
}

void ledc_init(void)
{
    // Prepare and then apply the LEDC PWM timer configuration
    ledc_timer_config_t ledc_timer = {
        .speed_mode       = LEDC_MODE,
        .timer_num        = LEDC_TIMER,
        .duty_resolution  = LEDC_DUTY_RES,
        .freq_hz          = LEDC_FREQUENCY,  // Set output frequency at 5 kHz
        .clk_cfg          = LEDC_AUTO_CLK
    };
    ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));

    // Prepare and then apply the LEDC PWM channel configuration
    ledc_channel_config_t ledc_channel = {
        .speed_mode     = LEDC_MODE,
        .channel        = LEDC_CHANNEL_R,
        .timer_sel      = LEDC_TIMER,
        .intr_type      = LEDC_INTR_DISABLE,
        .gpio_num       = LEDC_OUTPUT_IO_1,
        .duty           = 0, // Set duty to 0%
        .hpoint         = 0
    };
    ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
    ledc_channel.gpio_num = LEDC_OUTPUT_IO_2;
    ledc_channel.channel = LEDC_CHANNEL_G;
    ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
    ledc_channel.gpio_num = LEDC_OUTPUT_IO_3;
    ledc_channel.channel = LEDC_CHANNEL_B;
    ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
    if(read_color_data(&saved) == ESP_OK){
        ESP_LOGI(TAG, "Read saved led color rgb(%d,%d,%d)",saved.r,saved.g,saved.b);
        color->r = saved.r;
        color->g = saved.g;
        color->b = saved.b;
    }else{
        ESP_LOGI(TAG, "Read saved led color failed!");
    }

    led_timer = xTimerCreate
            (
                "Timer",
                58000,
                true,
                NULL,
                vTimerCallback
            );
}

int ledc_set_RGB(uint8_t R,uint8_t G,uint8_t B){

    switch (led_type)
    {
    case COMMON_CATHODE:
        ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL_R, 8191*R/255));
        ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL_G, 8191*G/255));
        ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL_B, 8191*B/255));
        break;
    case COMMON_ANNODE:
        ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL_R, 8191*(255-R)/255));
        ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL_G, 8191*(255-G)/255));
        ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL_B, 8191*(255-B)/255));
        break;    
    default:
        return -1;
        break;
    }
    ESP_LOGI(TAG, "Set led color rgb(%d,%d,%d)",R,G,B);
    if(R==G && G==B && B==0){

    }else{
        color[0].r = R;
        color[0].g = G;
        color[0].b = B;
        save_color_data(color[0]);
    }
    // Update duty to apply the new value
    ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL_R));
    // Update duty to apply the new value
    ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL_G));
    // Update duty to apply the new value
    ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL_B));
    return 0;
}



// 获取LED状态
bool get_led_status() {
    return led_state;
}

led_color_t get_led_color(){
    return color[0];
}

// 设置LED状态
void set_led_status(bool is_on) {
    led_state = is_on;
    // 这里执行控制LED的操作
    if(led_state){
        ledc_set_RGB(color[0].r,color[0].g,color[0].b);
    }else{
        ledc_set_RGB(0,0,0);
    }
    ESP_LOGI(TAG, "Set led state: %d",led_state);

}

void set_led_state_reverse(){
    led_state = !led_state;
    // 这里执行控制LED的操作
    if(led_state){
        ledc_set_RGB(color[0].r,color[0].g,color[0].b);
    }else{
        ledc_set_RGB(0,0,0);
    }
    ESP_LOGI(TAG, "Set led state: %d",led_state); 
}

void set_led_type(led_type_t type){
    led_type = type;
}

void set_led_saturation_down(void){
    color[0] = adjustSaturation(color[0],-0.1);
    ledc_set_RGB(color[0].r,color[0].g,color[0].b);
}

void set_led_brightness_down(void){
    color[0] = adjustBrightness(color[0],30);
    ledc_set_RGB(color[0].r,color[0].g,color[0].b);
}

void set_led_change_color(void){
    color[0] = color[selected_color_index];
    if(++selected_color_index>=NUM_COLOR){
        selected_color_index = 1;
    }
    ledc_set_RGB(color[0].r,color[0].g,color[0].b);
}

void set_led_off_time(unsigned char minute){
    if((minute==0)&&(xTimerIsTimerActive(led_timer))){
        xTimerStop(led_timer,0);
    }else{
        led_rest_time = minute;
        if(!xTimerIsTimerActive(led_timer)){
            xTimerStart(led_timer,0);
        }
    }
}

unsigned char get_led_off_time(void){
    return led_rest_time;
}

void convertColorString(const char* colorString, unsigned char* r, unsigned char* g, unsigned char* b) {
    // 跳过字符串中的'#'字符
    colorString++;

    // 提取红色分量
    char rString[3];
    strncpy(rString, colorString, 2);
    rString[2] = '\0';
    *r = (unsigned char)strtol(rString, NULL, 16);

    // 提取绿色分量
    char gString[3];
    strncpy(gString, colorString + 2, 2);
    gString[2] = '\0';
    *g = (unsigned char)strtol(gString, NULL, 16);

    // 提取蓝色分量
    char bString[3];
    strncpy(bString, colorString + 4, 2);
    bString[2] = '\0';
    *b = (unsigned char)strtol(bString, NULL, 16);
}